#include "MutaLine.h"
#include <QPainterPath>
#include <QMatrix>
#include <math.h>
#include <QPainter>
#include <QLineF>
#include "Global.h"

MutaLine::MutaLine(QString objectID,QString owner,QPointF p1,QPointF p2,int layer)
    : MutaObject(objectID,Muta::Line,owner),
      QGraphicsPathItem(),
      layer(layer),
      time(0),
      boxColor(155,255,255,10),
      controlPointString(QString())
{
    setPos(p1);
    setFlag( QGraphicsItem::ItemIsSelectable, true );
    setFlag( QGraphicsItem::ItemIsMovable, true );
    setFlag(QGraphicsItem::ItemSendsGeometryChanges);
    addControlPoint(p1);
    controlPoints.first()->setFlag( QGraphicsItem::ItemIsSelectable, false );
    controlPoints.first()->setFlag( QGraphicsItem::ItemIsMovable, false );
    addControlPoint(QPointF(x()+p2.x(),y()+p2.y()));
    boxBrush.setColor(boxColor);
    boxBrush.setStyle(Qt::SolidPattern);
    boxPen.setWidth(1);
    boxPen.setColor(boxColor);
}

MutaLine::MutaLine(QString objectID,QString owner,QPointF p1,QPointF p2,int layer, int zero)
    : MutaObject(objectID,Muta::Line,owner),
      QGraphicsPathItem(),
      layer(layer),
      time(0),
      boxColor(155,255,255,10),
      controlPointString(QString())
{
    setPos(p1);
    setFlag( QGraphicsItem::ItemIsSelectable, true );
    setFlag( QGraphicsItem::ItemIsMovable, true );
    setFlag(QGraphicsItem::ItemSendsGeometryChanges);
    addControlPointNQ(p1);
    controlPoints.first()->setFlag( QGraphicsItem::ItemIsSelectable, false );
    controlPoints.first()->setFlag( QGraphicsItem::ItemIsMovable, false );
    //addControlPoint(QPointF(x()+p2.x(),y()+p2.y()));
    boxBrush.setColor(boxColor);
    boxBrush.setStyle(Qt::SolidPattern);
    boxPen.setWidth(1);
    boxPen.setColor(boxColor);
}

void MutaLine::buildPath()
{
    QPainterPath path;
    path.moveTo(controlPoints.at(0)->pos());
    for(int i=1;i<controlPoints.size();i++) {
        path.quadTo(
            (((curvePoints.at(i-1)->pos()) - ((controlPoints.at(i)->pos() - controlPoints.at(0)->pos())*0.5))*2)+((controlPoints.at(i)->pos() - controlPoints.at(i-1)->pos())*0.5),
            controlPoints.at(i)->pos()
        );
    }
    setPath(path);
}

int MutaLine::type() const
{
    return mutaType;
}

void MutaLine::cPointMoved(QPointF pos,int num)
{
    controlPoints.at(num)->setPos(Muta::quantizePoint(pos,Muta::BEAT_PIXELS,15));
    if(num!=0) {
        QPointF curvePoint = (controlPoints.at(num)->pos() - controlPoints.at(controlPoints.size()-2)->pos())*0.5 + controlPoints.at(controlPoints.size()-2)->pos();
        curvePoints.at(num-1)->setPos(curvePoint);
    } else {
        //QPointF curvePoint = (controlPoints.at(1)->pos() - controlPoints.at(controlPoints.size()-2)->pos())*0.5 + (controlPoints.at(controlPoints.size()-2)->pos());
        //curvePoints.at(0)->setPos(curvePoint);
        setPos(pos);
    }
    buildControlPointString();
    buildPath();
    setColor();
}

void MutaLine::curvePointMoved(QPointF pos,int num)
{
    buildPath();
    setColor();
    //emit controlPointAdded(objectID,controlPoints,curvePoints);
    buildControlPointString();
}

void MutaLine::addControlPoint(QPointF point) {
    controlPoints.append(new ControlPoint(Muta::quantizePoint(point,Muta::BEAT_PIXELS,15)-this->pos()+QPointF(0,7.5),controlPoints.size(),-5,-5,10,10,this));
    QObject::connect(controlPoints.at(controlPoints.size() -1),SIGNAL(mouseMoved(QPointF,int)),this,SLOT(cPointMoved(QPointF,int)));
    if(controlPoints.size()>1) {
        curvePoints.append(new ControlPoint(Muta::quantizePoint(point,Muta::BEAT_PIXELS,15)-this->pos()+QPointF(0,7.5),curvePoints.size(),-5,-5,10,10,this));
        QObject::connect(curvePoints.at(curvePoints.size() -1),SIGNAL(mouseMoved(QPointF,int)),this,SLOT(curvePointMoved(QPointF,int)));
    }
    buildPath();
    setColor();
    //emit controlPointAdded(objectID,controlPoints,curvePoints);
    buildControlPointString();
}

void MutaLine::addControlPointNQ(QPointF point) {
    controlPoints.append(new ControlPoint(point-this->pos(),controlPoints.size(),-5,-5,10,10,this));
    QObject::connect(controlPoints.at(controlPoints.size() -1),SIGNAL(mouseMoved(QPointF,int)),this,SLOT(cPointMoved(QPointF,int)));
    if(controlPoints.size()>1) {
        curvePoints.append(new ControlPoint(point-this->pos(),curvePoints.size(),-5,-5,10,10,this));
        QObject::connect(curvePoints.at(curvePoints.size() -1),SIGNAL(mouseMoved(QPointF,int)),this,SLOT(curvePointMoved(QPointF,int)));
    }
    buildPath();
    setColor();
    //emit controlPointAdded(objectID,controlPoints,curvePoints);
    buildControlPointString();
}

void MutaLine::setCurvePoint(int num, QPointF point)
{
    curvePoints.at(num)->setPos(point - QPointF(0,0) - QPointF(0,7.5));
    buildPath();
    setColor();
    buildControlPointString();
}

void MutaLine::setPos(const QPointF &pos)
{
    QGraphicsPathItem::setPos(Muta::quantizePoint(pos,Muta::BEAT_PIXELS,15)+QPointF(0,7.5));
    emit posChanged(objectID,pos);
}


void MutaLine::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
    QGraphicsPathItem::mouseMoveEvent(event);
    setPos(this->pos());
}


void MutaLine::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    //time = (time+1)%7;
    //if(time > 6 ) {
        painter->setBrush(boxBrush);
        painter->setPen(boxPen);
        painter->drawRect(path().boundingRect());

        QGraphicsPathItem::paint(painter,option,widget);
    //}
}

void MutaLine::setFinalPoint(QPointF p)
{
    controlPoints.last()->setPos(Muta::quantizePoint(p,Muta::BEAT_PIXELS,15) - this->pos()+QPointF(0,7.5));
    QPointF curvePoint = (controlPoints.last()->pos() - controlPoints.at(controlPoints.size()-2)->pos())*0.5 + controlPoints.at(controlPoints.size()-2)->pos();
    curvePoints.last()->setPos(curvePoint);
    buildPath();
    setColor();
    //emit controlPointAdded(objectID,controlPoints,curvePoints);
    buildControlPointString();
}

void MutaLine::setColor()
{
    QColor fillColor;
    QColor firstCPointColor;
    QColor curvePColor;
    QColor clearColor = QColor(0,0,0,0);
    switch(layer) {
        case 0:
            fillColor = QColor(227,244,247,255);
            firstCPointColor = QColor(140,204,240,255);
            curvePColor = QColor(64,187,236,255);
            break;
        case 1:
            fillColor = QColor(216,191,215,255);
            firstCPointColor = QColor(194,118,177,255);
            curvePColor = QColor(124,40,125,255);
            break;
        case 2:
            fillColor = QColor(255,153,153);
            firstCPointColor = QColor(242, 99, 75,255);
            curvePColor = QColor(237, 31,36,255);
            break;
        case 3:
            fillColor = QColor(238,232,169,255);
            firstCPointColor = QColor(179,210,53,255);
            curvePColor = QColor(86,107,48,255);
            break;
        case 4:
            fillColor = QColor(	255,204,153,255);
            firstCPointColor = QColor(210,106,40,255);
            curvePColor = QColor(139,70,31,255);
            break;
    }

    QBrush brush;
    brush.setColor(fillColor);
    brush.setStyle(Qt::SolidPattern);

    QPen pen;
    pen.setJoinStyle(Qt::RoundJoin);
    pen.setCapStyle(Qt::RoundCap);
    pen.setBrush(brush);
    pen.setWidth(4);
    pen.setColor(fillColor);
    setPen(pen);
    pen.setWidth(1);

    for(int i=1;i<controlPoints.size();i++) {
        controlPoints.at(i)->setPen(pen);
        controlPoints.at(i)->setBrush(brush);
    }    

    brush.setColor(firstCPointColor);
    pen.setBrush(brush);
    pen.setWidth(1);
    pen.setColor(firstCPointColor);
    controlPoints.at(0)->setPen(pen);
    controlPoints.at(0)->setBrush(brush);

    brush.setColor(curvePColor);
    pen.setBrush(brush);
    pen.setWidth(3);
    pen.setColor(QColor(0,0,0,255));
    pen.setColor(curvePColor);
    for(int i=0;i<curvePoints.size();i++) {
        curvePoints.at(i)->setPen(pen);
        curvePoints.at(i)->setBrush(brush);
    }
}

QStringList MutaLine::getProperties()
{
    QStringList properties;
    properties << "ml" << owner << QString::number(x()) << QString::number(y()) << QString::number(layer);
    for(int i=0;i<controlPoints.size();i++) {
        properties << QString::number(controlPoints.at(i)->x()) << QString::number(controlPoints.at(i)->y());
    }
    properties << "crv";
    for(int i=0;i<curvePoints.size();i++) {
        properties << QString::number(curvePoints.at(i)->x()) << QString::number(curvePoints.at(i)->y());
    }

    return properties;
}

int MutaLine::getLayer()
{
    return layer;
}

QVariant MutaLine::itemChange(GraphicsItemChange change, const QVariant &value) {
    QVariant variant = QGraphicsPathItem::itemChange(change, value);

    if(change == QGraphicsItem::ItemPositionChange || change == QGraphicsItem::ItemPositionHasChanged)
    {
        //variant.setValue(Muta::quantizePoint(variant.toPointF(),Muta::BEAT_PIXELS,15)+QPointF(0,7.5));
        variant.setValue(Muta::quantizePoint(variant.toPointF(),Muta::BEAT_PIXELS,15));
    }

    return variant;
}

//OSCthulhu
void MutaLine::forceOSCthulhuUpdate()
{
    emit posChanged(objectID,pos());
}

void MutaLine::buildControlPointString()
{
    controlPointString.clear();
    for(int i=0;i<controlPoints.size();i++) {
        controlPointString.append(QString().number((int)(controlPoints.at(i)->pos().x())));
        controlPointString.append(",");
        controlPointString.append(QString().number((int)(controlPoints.at(i)->pos().y())));
        if(i!=controlPoints.size()-1) {
            controlPointString.append(",");
        }
    }
    controlPointString.append("&");
    for(int i=0;i<curvePoints.size();i++) {
        controlPointString.append(QString().number((int)(curvePoints.at(i)->pos().x())));
        controlPointString.append(",");
        controlPointString.append(QString().number((int)(curvePoints.at(i)->pos().y())));
        if(i!=curvePoints.size()-1) {
            controlPointString.append(",");
        }
    }
    emit controlPointAdded(objectID,controlPointString);
}

void MutaLine::setControlPoints(QString aCPS)
{
    if(this->controlPointString.compare(aCPS) != 0) {
        controlPointString = aCPS;
        QList<QPointF> tempControlPoints;
        QList<QPointF> tempCurvePoints;
        QStringList controlAndCurves = aCPS.split("&",QString::SkipEmptyParts);
        QStringList tempControlString = controlAndCurves.at(0).split(",",QString::SkipEmptyParts);
        for(int i=0;i<tempControlString.size();i+=2) {
            tempControlPoints.append(
                QPointF(tempControlString.at(i).toInt(),tempControlString.at(i+1).toInt())
            );
        }
        QStringList tempCurveString = controlAndCurves.at(1).split(",",QString::SkipEmptyParts);
        for(int i=0;i<tempCurveString.size();i+=2) {
            tempCurvePoints.append(
                QPointF(tempCurveString.at(i).toInt(),tempCurveString.at(i+1).toInt())
            );
        }
        for(int i=1;i<controlPoints.size();i++) {
            controlPoints.at(i)->setPos(tempControlPoints.at(i));
        }
        if(tempControlPoints.size()!=(controlPoints.size())) {
            for(int i=controlPoints.size();i<=tempControlPoints.size() -1;i++) {
                QPointF point = tempControlPoints.at(i);
                controlPoints.append(new ControlPoint(Muta::quantizePoint(point,Muta::BEAT_PIXELS,15),controlPoints.size(),-5,-5,10,10,this));
                QObject::connect(controlPoints.at(controlPoints.size() -1),SIGNAL(mouseMoved(QPointF,int)),this,SLOT(cPointMoved(QPointF,int)));
                if(controlPoints.size()>1) {
                    curvePoints.append(new ControlPoint(Muta::quantizePoint(point,Muta::BEAT_PIXELS,15),curvePoints.size(),-5,-5,10,10,this));
                    QObject::connect(curvePoints.at(curvePoints.size() -1),SIGNAL(mouseMoved(QPointF,int)),this,SLOT(curvePointMoved(QPointF,int)));
                }
            }
        }
        for(int i=0;i<curvePoints.size();i++) {
            curvePoints.at(i)->setPos(tempCurvePoints.at(i));
        }
        buildPath();
        setColor();
    }
}
